home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / telecomm / sticpsrc.lzh / SOURCE.ARC / LAPB.C < prev    next >
C/C++ Source or Header  |  1990-08-12  |  20KB  |  535 lines

  1. /* Link Access Procedures Balanced (LAPB) - with changes for rational
  2.  * behavior over packet radio
  3.  */
  4. #include "global.h"
  5. #include "mbuf.h"
  6. #include "timer.h"
  7. #include "ax25.h"
  8. #include "lapb.h"
  9.  
  10. /* Process incoming frames */
  11. int
  12. lapb_input(axp,cmdrsp,bp)
  13. register struct ax25_cb *axp;   /* Link control structure */
  14. char cmdrsp;                    /* Command/response flag */
  15. struct mbuf *bp;                /* Rest of frame, starting with ctl */
  16. {
  17.         char control,p_control;
  18.         char frej = 0;          /* FRMR reject reason code */
  19.         char class;             /* General class (I/S/U) of frame */
  20.         int16 type,p_type;      /* Specific type (I/RR/RNR/etc) of frame */
  21.         char pf;                /* extracted poll/final bit */
  22.         char vr;                /* extracted V(R) for I-frame */
  23.         char polled = 0;
  24.         char csum;              /* checksum for sammler */
  25.         int16 ftype();
  26.  
  27.         if(bp == NULLBUF || axp == NULLAX25){
  28.                 free_p(bp);
  29.                 return -1;
  30.         }
  31.         p_control = axp->control;
  32.         axp->control = control = pullchar(&bp);
  33.         type = ftype(control);
  34.         class = type & 0x3;
  35.         pf = control & PF;
  36.  
  37.         /* Check for polls */
  38.         if(cmdrsp == COMMAND && pf)
  39.                 polled = YES;
  40.  
  41.         /* While we're disconnected, ignore all except SABM and DISC */
  42.         if(axp->state == DISCONNECTED && type != SABM && type != DISC){
  43.                 if(polled)
  44.                         axp->response = DM;
  45.                 goto done;
  46.         }
  47.         /* Process implicit acknowledgements in all but U-frames */
  48.         if(class != U && ackours(axp,(control >> 5) & MMASK) == -1)
  49.                 frej = Z;       /* Out of range sequence number */
  50.  
  51.         if(type != I && type != FRMR && len_mbuf(bp) != 0)
  52.                 frej |= X|W;    /* I-field not allowed */
  53.  
  54.         /* Process final bit if a poll was outstanding */
  55.         if(axp->waitack && class != U && pf && cmdrsp == RESPONSE){
  56.                 axp->waitack = NO;
  57.                 axp->retries = 0;
  58.                 stop_timer(&axp->t1);
  59.                 /* Pick up retransmission at proper point */
  60.                 axp->vs = (axp->vs - axp->unack) & MMASK;
  61.                 axp->unack = 0;
  62.                 axp->control = REJ;     /* dirty: lapb_output sends single frame */
  63.         }
  64.         /* Resend FRMR for all except certain U while in error state */
  65.         if(axp->state == FRAMEREJECT && class != U){
  66.                 goto done;
  67.         }
  68.         switch(type){
  69.         case SABM:      /* Initialize or reset link */
  70.                 switch(axp->state){
  71.                 case DISCONNECTED:
  72.                         lapbstate(axp,CONNECTED,LAPBCONN);
  73.                         /* state-change upcall can force a DM by setting the
  74.                            state to DISCONNECTED */
  75.                         axp->response = (axp->state == CONNECTED)? UA : DM;
  76.                         break;
  77.                 case FRAMEREJECT:
  78.                         lapbstate(axp,CONNECTED,LAPBRESF);
  79.                         axp->response = UA;
  80.                         break;
  81.                 case CONNECTED:
  82.                         lapbstate(axp,CONNECTED,LAPBNOMS);
  83.                         axp->response = UA;
  84.                         break;
  85.                 case DISCPENDING:
  86.                         axp->response = DM;
  87.                         break;
  88.                 case SETUP:
  89.                         axp->response = UA;
  90.                         break;
  91.                 }
  92.                 break;
  93.         case UA:
  94.                 axp->retries = 0;
  95.                 switch(axp->state){
  96.                 case CONNECTED:
  97.                         /* ignore an UA just after SABM or UA */
  98.                         if ((p_type = ftype(p_control)) != UA &&
  99.                              p_type != SABM){
  100.                             lapbstate(axp,SETUP,LAPBNOMS);
  101.                             sendctl(axp,COMMAND,SABM|PF);
  102.                         }
  103.                         break;
  104.                 case SETUP:
  105.                         stop_timer(&axp->t1);
  106.                         lapbstate(axp,CONNECTED,LAPBCONN);
  107.                         break;
  108.                 case DISCPENDING:
  109.                         lapbstate(axp,DISCONNECTED,LAPBDISC);
  110.                         break;
  111.                 /* note - ignored if DISCONNECTED or in FRAMEREJECT state */
  112.                 }
  113.                 break;
  114.         case DISC:
  115.                 switch(axp->state){
  116.                 case SETUP:
  117.                         lapbstate(axp,DISCONNECTED,LAPBDISC);
  118.                         axp->response = DM;
  119.                         break;
  120.                 case DISCPENDING:
  121.                         axp->response = UA;
  122.                         break;
  123.                 default:
  124.                         lapbstate(axp,DISCONNECTED,LAPBDISC);
  125.                         axp->response = UA;
  126.                         break;
  127.                 }
  128.                 break;
  129.         case RR:
  130.                 axp->remotebusy = NO;
  131.                 break;
  132.         case RNR:
  133.                 axp->remotebusy = YES;
  134.                 axp->retries = 0;
  135.                 start_timer(&axp->t1);  /* Probe as long as necessary */
  136.                 break;
  137.         case REJ:
  138.                 /* Crank back V(s) to start of queue */
  139.                 axp->vs = (axp->vs - axp->unack) & MMASK;
  140.                 axp->unack = 0;
  141.                 break;
  142.         case I:
  143.                 if (axp->state != CONNECTED){   /* apparently missed UA */
  144.                         if (!run_timer(&axp->t1)) /* make sure timer is running */
  145.                                 start_timer(&axp->t1);
  146.                         break;                  /* ignore the I-frame */
  147.                 }
  148.                 if(len_mbuf(axp->rxq) >= axp->window){
  149.                         /* Too bad he didn't listen to us; he'll
  150.                          * have to resend the frame later. This
  151.                          * drastic action is necessary to avoid
  152.                          * deadlock.
  153.                          */
  154.                         axp->response = RNR;
  155.                         break;
  156.                 }
  157.                 /* Extract V(R) and throw away the framesammler contents */
  158.                 /* (A received frame always overrides the framesammler) */
  159.                 free_p(axp->sammlq[vr = (control>>1) & MMASK]);
  160.                 axp->sammlq[vr] = NULLBUF;
  161.  
  162.                 /* calculate a simple checksum over the frame. this is used */
  163.                 /* to discard retransmissions of the same frame when using  */
  164.                 /* the framesammler.  safety-first is the approach here.    */
  165.                 if (axp->maxsamml != 0 && bp != NULLBUF){
  166.                     register struct mbuf *cbp;
  167.                     register char *cdata;
  168.                     register int ccnt;
  169.  
  170.                     csum = 0;
  171.                     cbp = bp;
  172.  
  173.                     do {
  174.                         cdata = cbp->data;
  175.                         ccnt = cbp->cnt;
  176.                         do {
  177.                             csum += *cdata++;
  178.                         } while (--ccnt);
  179.                     } while ((cbp = cbp->next) != NULLBUF);
  180.                 }
  181.  
  182.                 /* Reject or ignore I-frames with receive sequence number errors */
  183.                 if(vr != axp->vr){
  184.                         /* Check if we can store it in the framesammler */
  185.                         /* we won't store frames with checksum equal to */
  186.                         /* an equal-numbered (earlier) frame            */
  187.                         if(axp->t2.start != 0 && csum != axp->sammlchk[vr] &&
  188.                            ((vr - axp->vr) & MMASK) <= axp->maxsamml){
  189.                                 axp->sammlq[vr] = bp;
  190.                                 bp = NULLBUF;
  191.                         }
  192.                         if(axp->proto == V1 || !axp->rejsent){
  193.                                 axp->rejsent = YES;
  194.                                 axp->response = REJ;
  195.                         }